/**
 * Copyright (C) 2021-2022 maminjie <canpool@163.com>
 * SPDX-License-Identifier: LGPL-2.1
 * Powered by Qt-Advanced-Docking-System
**/

#include "dockfloatingwidget.h"

#include "dockpannel.h"
#include "dockcontainer.h"
#include "dockmanager.h"
#include "dockmanager_p.h"
#include "dockoverlay.h"
#include "dockwidget.h"

#ifdef Q_OS_WIN
#include <windows.h>
#ifdef _MSC_VER
#pragma comment(lib, "User32.lib")
#endif
#endif

#ifdef Q_OS_LINUX
#include "linux/dockfloatingwidgettitlebar.h"
#include <xcb/xcb.h>
#endif

#include <QAbstractButton>
#include <QAction>
#include <QApplication>
#include <QBoxLayout>
#include <QDebug>
#include <QElapsedTimer>
#include <QLoggingCategory>
#include <QMouseEvent>
#include <QPointer>

QADS_BEGIN_NAMESPACE

static unsigned int zOrderCounter = 0;

/* DockFloatingWidgetPrivate */
class DockFloatingWidgetPrivate
{
public:
    DockFloatingWidgetPrivate(DockFloatingWidget *parent);

    void titleMouseReleaseEvent();
    void updateDropOverlays(const QPoint &globalPos);

    bool isState(DragState stateId) const {
        return stateId == m_draggingState;
    }
    void setState(DragState stateId) {
        m_draggingState = stateId;
    }

    void setWindowTitle(const QString &text);

    /**
     * Reflect the current dock widget title in the floating widget windowTitle()
     * depending on the QAds::FloatingContainerHasWidgetTitle flag
     */
    void reflectCurrentWidget(DockWidget *currentWidget);

    /**
     * Handles escape key press when dragging around the floating widget
     */
    void handleEscapeKey();

public:
    DockFloatingWidget *q;
    DockContainer *m_dockContainer = nullptr;
    unsigned int m_zOrderIndex = ++zOrderCounter;
    QPointer<DockManager> m_dockManager;
    DragState m_draggingState = DraggingInactive;
    QPoint m_dragStartPos;
    DockContainer *m_dropContainer = nullptr;
    DockPannel *m_signalPannel = nullptr;
    bool m_hiding = false;
    bool m_autoHideChildren = true;
#ifdef Q_OS_LINUX
    QWidget *m_mouseEventHandler = nullptr;
    DockFloatingWidgetTitleBar *m_titleBar = nullptr;
    bool m_isResizing = false;
#endif
}; // class DockFloatingWidgetPrivate

DockFloatingWidgetPrivate::DockFloatingWidgetPrivate(DockFloatingWidget *parent)
    : q(parent)
{}

void DockFloatingWidgetPrivate::titleMouseReleaseEvent()
{
    setState(DraggingInactive);

    if (!m_dropContainer) {
        return;
    }

    if (m_dockManager->pannelOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
            || m_dockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea) {
        DockOverlay *overlay = m_dockManager->containerOverlay();

        if (!overlay->dropOverlayRect().isValid()) {
            overlay = m_dockManager->pannelOverlay();
        }

        // Resize the floating widget to the size of the highlighted drop area rectangle
        QRect rect = overlay->dropOverlayRect();
        int frameWidth = (q->frameSize().width() - q->rect().width()) / 2;
        int titleBarHeight = q->frameSize().height() - q->rect().height() - frameWidth;

        if (rect.isValid()) {
            QPoint topLeft = overlay->mapToGlobal(rect.topLeft());
            topLeft.ry() += titleBarHeight;
            q->setGeometry(QRect(topLeft, QSize(rect.width(), rect.height() - titleBarHeight)));
            QApplication::processEvents();
        }

        m_dropContainer->dropFloatingWidget(q, QCursor::pos());
    }

    m_dockManager->containerOverlay()->hideOverlay();
    m_dockManager->pannelOverlay()->hideOverlay();
}

void DockFloatingWidgetPrivate::updateDropOverlays(const QPoint &globalPos)
{
    if (!q->isVisible() || !m_dockManager) {
        return;
    }
#ifdef Q_OS_LINUX
    // Prevent display of drop overlays and docking as long as a model dialog
    // is active
    if (qApp->activeModalWidget()) {
        return;
    }
#endif

    auto containers = m_dockManager->dockContainers();
    DockContainer *topContainer = nullptr;

    for (auto containerWidget : qAsConst(containers)) {
        if (!containerWidget->isVisible()) {
            continue;
        }

        if (m_dockContainer == containerWidget) {
            continue;
        }

        QPoint mappedPos = containerWidget->mapFromGlobal(globalPos);

        if (containerWidget->rect().contains(mappedPos)) {
            if (!topContainer || containerWidget->isFrontOf(topContainer)) {
                topContainer = containerWidget;
            }
        }
    }

    m_dropContainer = topContainer;
    auto containerOverlay = m_dockManager->containerOverlay();
    auto pannelOverlay = m_dockManager->pannelOverlay();

    if (!topContainer) {
        containerOverlay->hideOverlay();
        pannelOverlay->hideOverlay();
        return;
    }

    int visiblePannels = topContainer->visibleDockPannelCount();
    containerOverlay->setAllowedAreas(visiblePannels > 1 ? OuterDockAreas : AllDockAreas);
    DockWidgetArea containerArea = containerOverlay->showOverlay(topContainer);
    containerOverlay->enableDropPreview(containerArea != InvalidDockWidgetArea);
    auto pannel = topContainer->dockPannelAt(globalPos);

    if (pannel && pannel->isVisible() && visiblePannels > 0) {
        pannelOverlay->enableDropPreview(true);
        pannelOverlay->setAllowedAreas((visiblePannels == 1) ? NoDockWidgetArea : pannel->allowedAreas());
        DockWidgetArea area = pannelOverlay->showOverlay(pannel);

        // A CenterDockWidgetArea for the pannelOverlay() indicates that the mouse is in
        // the title bar. If the ContainerArea is valid then we ignore the dock area of the
        // pannelOverlay() and disable the drop preview
        if ((area == CenterDockWidgetArea) && (containerArea != InvalidDockWidgetArea)) {
            pannelOverlay->enableDropPreview(false);
            containerOverlay->enableDropPreview(true);
        } else {
            containerOverlay->enableDropPreview(InvalidDockWidgetArea == area);
        }
    } else {
        pannelOverlay->hideOverlay();
    }
}

void DockFloatingWidgetPrivate::setWindowTitle(const QString &text)
{
#if defined(Q_OS_LINUX)
    if (m_titleBar) {
        m_titleBar->setTitle(text);
    }
#else
    q->setWindowTitle(text);
#endif
}

void DockFloatingWidgetPrivate::reflectCurrentWidget(DockWidget *currentWidget)
{
    // reflect CurrentWidget's title if configured to do so, otherwise display application name as window title
    if (QAds::testConfigFlag(QAds::FloatingContainerHasWidgetTitle)) {
        setWindowTitle(currentWidget->windowTitle());
    } else {
        setWindowTitle(QApplication::applicationDisplayName());
    }

    // reflect currentWidget's icon if configured to do so, otherwise display application icon as window icon
    QIcon currentWidgetIcon = currentWidget->icon();

    if (QAds::testConfigFlag(QAds::FloatingContainerHasWidgetIcon) && !currentWidgetIcon.isNull()) {
        q->setWindowIcon(currentWidget->icon());
    } else {
        q->setWindowIcon(QApplication::windowIcon());
    }
}

void DockFloatingWidgetPrivate::handleEscapeKey()
{
    setState(DraggingInactive);
    m_dockManager->containerOverlay()->hideOverlay();
    m_dockManager->pannelOverlay()->hideOverlay();
}

DockFloatingWidget::DockFloatingWidget(DockManager *dockManager)
    : DockFloatingWidgetBase(dockManager)
    , d(new DockFloatingWidgetPrivate(this))
{
    d->m_dockManager = dockManager;
    d->m_dockContainer = new DockContainer(dockManager, this);
    connect(d->m_dockContainer, &DockContainer::dockPannelsAdded,
            this, &DockFloatingWidget::onDockPannelsAddedOrRemoved);
    connect(d->m_dockContainer, &DockContainer::dockPannelsRemoved,
            this, &DockFloatingWidget::onDockPannelsAddedOrRemoved);
#ifdef Q_OS_LINUX
    QDockWidget::setWidget(d->m_dockContainer);
    QDockWidget::setFloating(true);
    QDockWidget::setFeatures(QDockWidget::DockWidgetClosable
                             | QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);

    bool native_window = true;

    // FloatingContainerForce*TitleBar is overwritten by the "QADS_UseNativeTitle" environment variable if set.
    auto env = qgetenv("QADS_UseNativeTitle").toUpper();
    if (env == "1") {
        native_window = true;
    } else if (env == "0") {
        native_window = false;
    } else if (QAds::testConfigFlag(QAds::FloatingContainerForceNativeTitleBar)) {
        native_window = true;
    } else if (QAds::testConfigFlag(QAds::FloatingContainerForceQWidgetTitleBar)) {
        native_window = false;
    } else {
        // KDE doesn't seem to fire MoveEvents while moving windows, so for now no native titlebar for everything using KWin.
        QString window_manager = internal::windowManager().toUpper().split(" ")[0];
        native_window = window_manager != "KWIN";
    }

    if (native_window) {
        setTitleBarWidget(new QWidget());
        setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
    } else {
        d->m_titleBar = new DockFloatingWidgetTitleBar(this);
        setTitleBarWidget(d->m_titleBar);
//        setWindowFlags(windowFlags() | Qt::Tool);
        setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint);
        d->m_titleBar->enableCloseButton(isClosable());
        connect(d->m_titleBar, &DockFloatingWidgetTitleBar::closeRequested, this, &DockFloatingWidget::close);
        connect(d->m_titleBar, &DockFloatingWidgetTitleBar::maximizeRequested,
                this, &DockFloatingWidget::onMaximizeRequest);
    }
#else
    setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
    QBoxLayout *boxLayout = new QBoxLayout(QBoxLayout::TopToBottom);
    boxLayout->setContentsMargins(0, 0, 0, 0);
    boxLayout->setSpacing(0);
    setLayout(boxLayout);
    boxLayout->addWidget(d->m_dockContainer);
#endif
    dockManager->registerFloatingWidget(this);
}

DockFloatingWidget::DockFloatingWidget(DockPannel *dockPannel)
    : DockFloatingWidget(dockPannel->dockManager())
{
    d->m_dockContainer->addDockPannel(dockPannel);

    if (auto dw = topLevelDockWidget()) {
        dw->emitTopLevelChanged(true);
    }

    d->m_dockManager->notifyWidgetOrPannelRelocation(dockPannel);
}

DockFloatingWidget::DockFloatingWidget(DockWidget *dockWidget)
    : DockFloatingWidget(dockWidget->dockManager())
{
    d->m_dockContainer->addDockWidget(CenterDockWidgetArea, dockWidget);

    if (auto dw = topLevelDockWidget()) {
        dw->emitTopLevelChanged(true);
    }

    d->m_dockManager->notifyWidgetOrPannelRelocation(dockWidget);
}

DockFloatingWidget::~DockFloatingWidget()
{
    if (d->m_dockManager) {
        d->m_dockManager->removeFloatingWidget(this);
    }

    delete d;
}

DockContainer *DockFloatingWidget::dockContainer() const
{
    return d->m_dockContainer;
}

bool DockFloatingWidget::isClosable() const
{
    return d->m_dockContainer->features().testFlag(DockWidget::DockWidgetClosable);
}

bool DockFloatingWidget::hasTopLevelDockWidget() const
{
    return d->m_dockContainer->hasTopLevelDockWidget();
}

DockWidget *DockFloatingWidget::topLevelDockWidget() const
{
    return d->m_dockContainer->topLevelDockWidget();
}

QList<DockWidget *> DockFloatingWidget::dockWidgets() const
{
    return d->m_dockContainer->dockWidgets();
}

void DockFloatingWidget::hideAndDeleteLater()
{
    // Widget has been redocked, so it must be hidden right way (see
    // https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/351)
    // but m_autoHideChildren must be set to false because "this" still contains
    // dock widgets that shall not be toggled hidden.
    d->m_autoHideChildren = false;
    hide();
    deleteLater();
}

#ifdef Q_OS_LINUX
/**
 * This is a function that responds to FloatingWidgetTitleBar::maximizeRequest()
 * Maximize or normalize the container size.
 */
void DockFloatingWidget::onMaximizeRequest()
{
    if (windowState() == Qt::WindowMaximized) {
        showNormal();
    } else {
        showMaximized();
    }
}

/**
 * Normalize (Unmaximize) the window.
 *	fixGeometry parameter fixes a "bug" in QT where immediately after calling showNormal
 *	geometry is not set properly.
 *	Set this true when moving the window immediately after normalizing.
 */
void DockFloatingWidget::showNormal(bool fixGeometry)
{
    if (windowState() == Qt::WindowMaximized) {
        QRect oldNormal = normalGeometry();
        Super::showNormal();
        if (fixGeometry) {
            setGeometry(oldNormal);
        }
    }
    if (d->m_titleBar) {
        d->m_titleBar->setMaximizedIcon(false);
    }
}

/**
 * Maximizes the window.
 */
void DockFloatingWidget::showMaximized()
{
    Super::showMaximized();
    if (d->m_titleBar) {
        d->m_titleBar->setMaximizedIcon(true);
    }
}

/**
 * Returns if the window is currently maximized or not.
 */
bool DockFloatingWidget::isMaximized() const
{
    return windowState() == Qt::WindowMaximized;
}

/**
 * Patched show to prevent the window from appearing in the taskbar.
 */
void DockFloatingWidget::show()
{
    // Prevent this window from showing in the taskbar and pager (alt+tab)
    internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_TASKBAR");
    internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_PAGER");
    Super::show();
}

/**
 * Returns true if the floating widget has a native titlebar or false if
 * the floating widget has a QWidget based title bar
 */
bool DockFloatingWidget::hasNativeTitleBar()
{
    return d->m_titleBar == nullptr;
}
#endif

void DockFloatingWidget::startFloating(const QPoint &dragStartPos, const QSize &size,
                                       DragState dragState, QWidget *mouseEventHandler)
{
#ifdef Q_OS_LINUX
    if (!isMaximized()) {
        resize(size);
        d->m_dragStartPos = dragStartPos;
    }
    d->setState(dragState);
    if (DraggingFloatingWidget == dragState) {
        setAttribute(Qt::WA_X11NetWmWindowTypeDock, true);
        d->m_mouseEventHandler = mouseEventHandler;

        if (d->m_mouseEventHandler) {
            d->m_mouseEventHandler->grabMouse();
        }
    }
    if (!isMaximized()) {
        moveFloating();
    }
    show();
#else
    Q_UNUSED(mouseEventHandler)
    resize(size);
    d->setState(dragState);
    d->m_dragStartPos = dragStartPos;
    moveFloating();
    show();
#endif
}

void DockFloatingWidget::moveFloating()
{
    const int borderSize = (frameSize().width() - size().width()) / 2;
    const QPoint moveToPos = QCursor::pos() - d->m_dragStartPos - QPoint(borderSize, 0);
    move(moveToPos);

    switch (d->m_draggingState) {
    case DraggingMousePressed:
        d->setState(DraggingFloatingWidget);
        d->updateDropOverlays(QCursor::pos());
        break;

    case DraggingFloatingWidget:
        d->updateDropOverlays(QCursor::pos());
#if defined(Q_OS_MACOS)
        // On macOS when hiding the DockAreaOverlay the application would set
        // the main window as the active window for some reason. This fixes
        // that by resetting the active window to the floating widget after
        // updating the overlays.
        QApplication::setActiveWindow(this);
#endif
        break;

    default:
        break;
    }
}

void DockFloatingWidget::finishDragging()
{
#ifdef Q_OS_LINUX
    setAttribute(Qt::WA_X11NetWmWindowTypeDock, false);
    setWindowOpacity(1);
    activateWindow();

    if (d->m_mouseEventHandler) {
        d->m_mouseEventHandler->releaseMouse();
        d->m_mouseEventHandler = nullptr;
    }
#endif
    d->titleMouseReleaseEvent();
}

void DockFloatingWidget::updateWindowTitle()
{
    // If this floating container will be hidden, then updating the window
    // title is not required anymore
    if (d->m_hiding) {
        return;
    }

    if (auto topLevelDockPannel = d->m_dockContainer->topLevelDockPannel()) {
        if (DockWidget *currentWidget = topLevelDockPannel->currentDockWidget()) {
            d->reflectCurrentWidget(currentWidget);
        }
    } else {
        d->setWindowTitle(QApplication::applicationDisplayName());
        setWindowIcon(QApplication::windowIcon());
    }
}

bool DockFloatingWidget::restoreState(DockStateReader &stream, bool testing)
{
    if (!d->m_dockContainer->restoreState(stream, testing)) {
        return false;
    }

    onDockPannelsAddedOrRemoved();
#ifdef Q_OS_LINUX
    if (d->m_titleBar) {
        d->m_titleBar->setMaximizedIcon(windowState() == Qt::WindowMaximized);
    }
#endif
    return true;
}

void DockFloatingWidget::changeEvent(QEvent *event)
{
    QWidget::changeEvent(event);

    if ((event->type() == QEvent::ActivationChange) && isActiveWindow()) {
        d->m_zOrderIndex = ++zOrderCounter;
#ifdef Q_OS_LINUX
        if (d->m_draggingState == DraggingFloatingWidget) {
            d->titleMouseReleaseEvent();
            d->m_draggingState = DraggingInactive;
        }
#endif
    }
}

void DockFloatingWidget::closeEvent(QCloseEvent *event)
{
    d->setState(DraggingInactive);
    event->ignore();

    if (!isClosable()) {
        return;
    }

    bool hasOpenDockWidgets = false;
    for (auto dockWidget : d->m_dockContainer->openedDockWidgets()) {
        if (dockWidget->features().testFlag(DockWidget::DockWidgetDeleteOnClose) ||
            dockWidget->features().testFlag(DockWidget::CustomCloseHandling)) {
            bool closed = dockWidget->closeDockWidgetInternal();
            if (!closed) {
                hasOpenDockWidgets = true;
            }
        } else {
            dockWidget->toggleView(false);
        }
    }
    if (hasOpenDockWidgets) {
        return;
    }
    // In Qt version after 5.9.2 there seems to be a bug that causes the
    // QWidget::event() function to not receive any NonClientArea mouse
    // events anymore after a close/show cycle. The bug is reported here:
    // https://bugreports.qt.io/browse/QTBUG-73295
    // The following code is a workaround for Qt versions > 5.9.2 that seems
    // to work
    // Starting from Qt version 5.12.2 this seems to work again. But
    // now the QEvent::NonClientAreaMouseButtonPress function returns always
    // Qt::RightButton even if the left button was pressed
    this->hide();
}

void DockFloatingWidget::hideEvent(QHideEvent *event)
{
    Super::hideEvent(event);

    if (event->spontaneous()) {
        return;
    }

    // Prevent toogleView() events during restore state
    if (d->m_dockManager->isRestoringState()) {
        return;
    }

    if (d->m_autoHideChildren) {
        d->m_hiding = true;
        for (auto pannel : d->m_dockContainer->openedDockPannels()) {
            for (auto dockWidget : pannel->openedDockWidgets()) {
                dockWidget->toggleView(false);
            }
        }
        d->m_hiding = false;
    }
}

void DockFloatingWidget::showEvent(QShowEvent *event)
{
    Super::showEvent(event);
#ifdef Q_OS_LINUX
    if (QAds::testConfigFlag(QAds::FocusHighlighting)) {
        window()->activateWindow();
    }
#endif
}

#ifdef Q_OS_LINUX
static bool s_mousePressed = false;
void DockFloatingWidget::moveEvent(QMoveEvent *event)
{
    Super::moveEvent(event);
    if (!d->m_isResizing && event->spontaneous() && s_mousePressed) {
        d->m_draggingState = DraggingFloatingWidget;
        d->updateDropOverlays(QCursor::pos());
    }
    d->m_isResizing = false;
}

void DockFloatingWidget::resizeEvent(QResizeEvent *event)
{
    d->m_isResizing = true;
    Super::resizeEvent(event);
}

bool CFloatingDockContainer::event(QEvent *e)
{
    bool result = Super::event(e);
    switch (e->type()) {
    case QEvent::WindowActivate:
        s_mousePressed = false;
        break;
    case QEvent::WindowDeactivate:
        s_mousePressed = true;
        break;
    default:
        break;
    }
    return result;
}
#endif

#ifdef Q_OS_MACOS
bool DockFloatingWidget::event(QEvent *event)
{
    switch (d->m_draggingState) {
    case DraggingInactive: {
        // Normally we would check here, if the left mouse button is pressed.
        // But from QT version 5.12.2 on the mouse events from
        // QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
        // The event always returns Qt::RightButton even if the left button
        // is clicked.
        // It is really great to work around the whole NonClientMouseArea
        // bugs
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
        if (event->type() == QEvent::NonClientAreaMouseButtonPress
                /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
#else
        if (event->type() == QEvent::NonClientAreaMouseButtonPress
                && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
#endif
        {
            d->m_dragStartPos = pos();
            d->setState(DraggingMousePressed);
        }
    } break;
    case DraggingMousePressed:
        switch (event->type()) {
        case QEvent::NonClientAreaMouseButtonDblClick:
            d->setState(DraggingInactive);
            break;
        case QEvent::Resize:
            // If the first event after the mouse press is a resize event, then
            // the user resizes the window instead of dragging it around.
            // But there is one exception. If the window is maximized,
            // then dragging the window via title bar will cause the widget to
            // leave the maximized state. This in turn will trigger a resize event.
            // To know, if the resize event was triggered by user via moving a
            // corner of the window frame or if it was caused by a windows state
            // change, we check, if we are not in maximized state.
            if (!isMaximized()) {
                d->setState(DraggingInactive);
            }
            break;
        default:
            break;
        }
        break;
    case DraggingFloatingWidget:
        if (event->type() == QEvent::NonClientAreaMouseButtonRelease) {
            d->titleMouseReleaseEvent();
        }
        break;
    default:
        break;
    }

#if (QADS_DEBUG_LEVEL > 0)
    qDebug() << Q_FUNC_INFO << event->type();
#endif
    return QWidget::event(event);
}

void DockFloatingWidget::moveEvent(QMoveEvent *event)
{
    QWidget::moveEvent(event);

    switch (d->m_draggingState) {
    case DraggingMousePressed:
        d->setState(DraggingFloatingWidget);
        d->updateDropOverlays(QCursor::pos());
        break;

    case DraggingFloatingWidget:
        d->updateDropOverlays(QCursor::pos());
        // On macOS when hiding the DockAreaOverlay the application would set
        // the main window as the active window for some reason. This fixes
        // that by resetting the active window to the floating widget after
        // updating the overlays.
        QApplication::setActiveWindow(this);
        break;

    default:
        break;
    }
}
#endif

#ifdef Q_OS_WIN
# if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
bool DockFloatingWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
# else
bool DockFloatingWidget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
# endif
{
    QWidget::nativeEvent(eventType, message, result);
    MSG *msg = static_cast<MSG *>(message);

    switch (msg->message) {
    case WM_MOVING: {
        if (d->isState(DraggingFloatingWidget)) {
            d->updateDropOverlays(QCursor::pos());
        }
    }
        break;

    case WM_NCLBUTTONDOWN:
        if (msg->wParam == HTCAPTION && d->isState(DraggingInactive)) {
            d->m_dragStartPos = pos();
            d->setState(DraggingMousePressed);
        }

        break;

    case WM_NCLBUTTONDBLCLK:
        d->setState(DraggingInactive);
        break;

    case WM_ENTERSIZEMOVE:
        if (d->isState(DraggingMousePressed)) {
            d->setState(DraggingFloatingWidget);
            d->updateDropOverlays(QCursor::pos());
        }

        break;

    case WM_EXITSIZEMOVE:
        if (d->isState(DraggingFloatingWidget)) {
            if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
                d->handleEscapeKey();
            } else {
                d->titleMouseReleaseEvent();
            }
        }

        break;
    }

    return false;
}
#endif

void DockFloatingWidget::onDockPannelsAddedOrRemoved()
{
    auto topLevelDockPannel = d->m_dockContainer->topLevelDockPannel();

    if (topLevelDockPannel) {
        d->m_signalPannel = topLevelDockPannel;
        d->reflectCurrentWidget(d->m_signalPannel->currentDockWidget());
        connect(d->m_signalPannel, &DockPannel::currentChanged,
                this, &DockFloatingWidget::onDockPannelCurrentChanged);
    } else {
        if (d->m_signalPannel) {
            disconnect(d->m_signalPannel, &DockPannel::currentChanged,
                       this, &DockFloatingWidget::onDockPannelCurrentChanged);
            d->m_signalPannel = nullptr;
        }

        d->setWindowTitle(QApplication::applicationDisplayName());
        setWindowIcon(QApplication::windowIcon());
    }
}

void DockFloatingWidget::onDockPannelCurrentChanged(int index)
{
    Q_UNUSED(index)
    d->reflectCurrentWidget(d->m_signalPannel->currentDockWidget());
}

QADS_END_NAMESPACE
